package com.moonshineproject.plugin.menu
{
    import com.moonshineproject.IDEModel;
    import com.moonshineproject.plugin.PluginBase;
    import com.moonshineproject.plugin.menu.vo.CustomMenu;
    import com.moonshineproject.plugin.menu.vo.CustomMenuItem;
    import com.moonshineproject.plugin.menu.vo.MenuItem;
    import com.moonshineproject.plugin.project.ProjectPlugin;
    import com.moonshineproject.plugin.settings.ISettingsProvider;
    import com.moonshineproject.plugin.settings.SettingsPlugin;
    import com.moonshineproject.plugin.settings.vo.ISetting;
    import com.moonshineproject.plugin.settings.vo.MultiOptionSetting;
    import com.moonshineproject.plugin.settings.vo.NameValuePair;
    import com.moonshineproject.utils.KeyboardShortcutManager;
    import com.moonshineproject.vo.KeyboardShortcut;
    import com.moonshineproject.vo.Settings;
    
    import flash.desktop.NativeApplication;
    import flash.display.NativeMenu;
    import flash.display.NativeMenuItem;
    import flash.display.NativeWindow;
    import flash.events.Event;
    import flash.ui.Keyboard;
    
    import mx.core.FlexGlobals;

    // This class is a singleton
    public class MenuPlugin extends PluginBase implements ISettingsProvider
    {

        // If you add menus, make sure to add a constant for the event + a binding for a command in IDEController
        public static const MENU_QUIT_EVENT:String = "menuQuitEvent";

        public static const MENU_OPEN_EVENT:String = "menuOpenEvent";

        public static const MENU_SAVE_EVENT:String = "menuSaveEvent";

        public static const MENU_SAVE_AS_EVENT:String = "menuSaveAsEvent";

        public static const MENU_NEW_FILE_EVENT:String = "menuNewFileEvent";
		
		
		private const BUILD_NATIVE_MENU:uint = 1;
		private const BUILD_CUSTOM_MENU:uint = 2;
		private const BUILD_NATIVE_CUSTOM_MENU:uint = 3;


        override public function get name():String
        {
            return "Application Menu Plugin"
        }

        override public function get author():String
        {
            return "Keyston Clay & Moonshine Project Team"
        }

        override public function get description():String
        {
            return "Adds Menu"
        }

        override public function activate():void
        {
            super.activate();
            init();
        }

        override public function deactivate():void
        {
        }
		public function getSettingsList():Vector.<ISetting>
		{
			
			var nvps:Vector.<NameValuePair> = Vector.<NameValuePair>([
				new NameValuePair("Native",BUILD_NATIVE_MENU),
				new NameValuePair("Custom",BUILD_CUSTOM_MENU)
			]);			
			
			if(Settings.os !="win"){
				nvps.push(new NameValuePair("Native & Custom",BUILD_NATIVE_CUSTOM_MENU));
			}
			return Vector.<ISetting>([
				new MultiOptionSetting(this,"activeMenus","Select your menu",nvps)
			]);
		}

        // Data structure for Application window on Mac, Window menu on Windows and to-be-figured-out on Lunix.

		protected var windowMenus:Vector.<MenuItem> = Vector.<MenuItem>([
			new MenuItem("Moonshine", [
				new MenuItem("Quit", null, MENU_QUIT_EVENT,
					"q", [Keyboard.COMMAND],
					"f10", [Keyboard.CONTROL])
			]),
			new MenuItem("File", [
				new MenuItem("New", [
					new MenuItem("File", null, MENU_NEW_FILE_EVENT),
					new MenuItem("Project", null, ProjectPlugin.EVENT_NEW_AS3_PROJECT)
				]),
				new MenuItem("Open", null, MENU_OPEN_EVENT,
					'o', [Keyboard.COMMAND],
					'o', [Keyboard.CONTROL]),
				new MenuItem(null),
				new MenuItem("Save", null, MENU_SAVE_EVENT,
					's', [Keyboard.COMMAND],
					's', [Keyboard.CONTROL]),
				new MenuItem("Save As...", null, MENU_SAVE_AS_EVENT),
				new MenuItem("Settings", null, SettingsPlugin.EVENT_OPEN_SETTINGS,
					",", [Keyboard.COMMAND])
				
				
			])
		]);		
		
		public var activeMenus:uint = Settings.os !="win" ? BUILD_NATIVE_CUSTOM_MENU: BUILD_CUSTOM_MENU;
		
        private var pluginMenuObject:MenuItem = new MenuItem("Plugin", []);

        protected static var shortcutManager:KeyboardShortcutManager = KeyboardShortcutManager.getInstance();
	
		
        private var buildingNativeMenu:Boolean = false;

        public function addPluginMenu(menu:MenuItem):void
        {
            if (!menu)
                return;
            // If we have an assigned parent, loop down & place the menu there.
            if (menu.parents)
            {
                recurseAssignMenu(menu, windowMenus);
            }
            else // Otherwise we toss it in the 'Plugins' menu.
            {
                pluginMenuObject.items.push(menu);
            }
        }

        // Adds menu to internal menu representation at a given point. MenuItem.parents decide where it goes.
        protected function recurseAssignMenu(menuItem:MenuItem, children:Vector.<MenuItem>):void
        {
            var target:String = (menuItem.parents.length) ? menuItem.parents[0] : menuItem.label;

            for each (var m:MenuItem in children)
            {
                if (m.label == target)
                {
                    if (m.items == null)
                        m.items = new Vector.<MenuItem>(1);
                    menuItem.parents.splice(0, 1);
                    recurseAssignMenu(menuItem, m.items);
                    return;
                }
            }

            if (menuItem.parents.length == 0)
            {
                // Target menu found, just add children.
                for each (var submenuItem:MenuItem in menuItem.items)
                {
                    children.push(submenuItem);
                }
            }
            else
            {
                // Menu not found, add it.
                children.push(menuItem);
            }
        }

        private function init():void
        {
            if (!activated)
                return;

            if (pluginMenuObject.items.length)
                windowMenus.push(pluginMenuObject);
			
			if(activeMenus == BUILD_NATIVE_MENU || activeMenus ==BUILD_NATIVE_CUSTOM_MENU){
				buildingNativeMenu = true;
				createMenu();
			}
			
			if(activeMenus == BUILD_CUSTOM_MENU || activeMenus ==BUILD_NATIVE_CUSTOM_MENU){
				buildingNativeMenu = false;
				createMenu();
			}

        }

        private function createMenu():void
        {
            var mainMenu:* = buildingNativeMenu ? new NativeMenu() : new CustomMenu();
            addMenus(windowMenus, mainMenu);
            if (buildingNativeMenu)
            {

				var ide:Moonshine = Moonshine(FlexGlobals.topLevelApplication);
                if (NativeApplication.supportsMenu)
                    ide.nativeApplication.menu = mainMenu;
                if (NativeWindow.supportsMenu)
                    ide.nativeWindow.menu = mainMenu;
            }
            else
            {
				var menuBar:MenuBar = new MenuBar();                
              	 menuBar.menu = mainMenu;
                IDEModel.getInstance().mainView.addChildAt(menuBar, 0);
            }

        }


        protected function createNewMenu():*
        {
            return buildingNativeMenu ? new NativeMenu() : new CustomMenu();
        }

        private function createNewMenuItem(item:MenuItem):*
        {
			var nativeMenuItem:NativeMenuItem
			var menuItem:CustomMenuItem
            var shortcut:KeyboardShortcut = buildShortcut(item);
            if (buildingNativeMenu)
            {
				nativeMenuItem = new NativeMenuItem(item.label, item.isSeparator);

                if (item[Settings.os + "_key"])
                    nativeMenuItem.keyEquivalent = item[Settings.os + "_key"];
                if (item[Settings.os + "_mod"])
                    nativeMenuItem.keyEquivalentModifiers = item[Settings.os + "_mod"];
                if (item.event)
                    nativeMenuItem.data = item.event;
                nativeMenuItem.addEventListener(Event.SELECT, redispatch);

            }
            else
            {

				menuItem = new CustomMenuItem(item.label, item.isSeparator);

                if (shortcut)
                {
                    menuItem.shortcut = shortcut;
                }
                else if (item.event)
                {
                    menuItem.data = item.event;
                }

            }
            if (shortcut)
                registerShortcut(shortcut);

            return buildingNativeMenu? nativeMenuItem : menuItem;

        }

        private function buildShortcut(item:MenuItem):KeyboardShortcut
        {
            var key:String
            var mod:Array
            var event:String

            if (item[Settings.os + "_key"])
                key = item[Settings.os + "_key"];
            if (item[Settings.os + "_mod"])
                mod = item[Settings.os + "_mod"];
            if (item.event)
                event = item.event
            if (event && key)
                return new KeyboardShortcut(event, key, mod);
            return null;
        }

        private function registerShortcut(shortcut:KeyboardShortcut):void
        {
            shortcutManager.activate(shortcut);		
        }
		
		// Loop through menu structure and add menus through handler
		protected function addMenus(items:Vector.<MenuItem>, parentMenu:*):void
		{
			for (var i:int = 0; i < items.length; i++)
			{
				var item:MenuItem = items[i];
				
				if (item.items)
				{
					var newMenu:*;
					newMenu = createNewMenu();
					if(!newMenu) continue;
					addMenus(item.items, newMenu);
					parentMenu.addSubmenu(newMenu, item.label);
				}
				else
				{					
					var menuItem:* = createNewMenuItem(item);
					if(menuItem)				
						parentMenu.addItem(menuItem);
				}
			}
		}
        // Take events and redispatch them through GED.
        protected function redispatch(event:Event):void
        {
            var menuItem:NativeMenuItem = event.target as NativeMenuItem;

            if (menuItem)
            {
                var eventType:String = menuItem.data as String;

                if (eventType)
                {
                    shortcutManager.stopEvent(eventType); // use to stop pending event from shortcut					
                }
            }
        }





    }
}